#include "triangle.hpp"

Triangle::Triangle( vec3f &v0, vec3f &v1, vec3f &v2, vec3f &color ) {
  _p[0] = v0, _p[1] = v1, _p[2] = v2;
  _col = color;
}

bool Triangle::calculateBaryCentricCoordinate( const Ray &r, f32 &tval ) {
  // TODO:
  f32 ABC[3];
  f32 DEF[3];
  f32 GHI[3];
  f32 JKL[3];
  for ( ui8 i = 0; i < 3; i++ ) {
    ABC[i] = _p[0][i] - _p[1][i];
    DEF[i] = _p[0][i] - _p[2][i];
    GHI[i] = r.direction()[i];
    JKL[i] = _p[0][i] - r.origin()[i];
  }

  f32 EIHF_GFDI_DHEG[3] = {DEF[1] * GHI[2] - GHI[1] * DEF[2],
                           GHI[0] * DEF[2] - DEF[0] * GHI[2],
                           DEF[0] * GHI[1] - DEF[1] * GHI[0]};

  f32 denom = 0.f;
  f32 beta = 0.f;
  for ( ui8 i = 0; i < 3; i++ ) {
    denom += ABC[i] * EIHF_GFDI_DHEG[i];
    beta += JKL[i] * EIHF_GFDI_DHEG[i];
  }
  beta /= denom;

  if ( beta - FLT_EPSILON <= 0.0f || beta >= 1.0f ) return false;

  f32 AKJB_JCAL_BLKC[3] = {ABC[0] * JKL[1] - JKL[0] * ABC[1],
                           JKL[0] * ABC[2] - ABC[0] * JKL[2],
                           ABC[1] * JKL[2] - JKL[1] * ABC[2]};
  f32 gamma = 0.f;
  for ( ui8 i = 0; i < 3; i++ ) {
    gamma += GHI[2 - i] * AKJB_JCAL_BLKC[i];
  }
  gamma /= denom;
  if ( gamma - FLT_EPSILON <= 0.0f || beta + gamma >= 1.0f ) {
    return false;
  }
  for ( ui8 i = 0; i < 3; i++ ) {
    tval += DEF[2 - i] * AKJB_JCAL_BLKC[i];
  }
  tval /= -denom;
  return true;
}

bool Triangle::hit( const Ray &r, f32 tmin, f32 tmax, f32 time,
                    HitRecord &record ) {
  f32 tval;
  if ( calculateBaryCentricCoordinate( r, tval ) ) {
    if ( tval >= tmin && tval <= tmax ) {
      record.t = tval;
      record.normal = cross( _p[1] - _p[0], _p[2] - _p[0] );
      record.color = _col;
      return true;
    }
  } 
  return false;
}

bool Triangle::shadowHit( const Ray &r, f32 tmin, f32 tmax, f32 time ) {
    f32 tval;
    if (calculateBaryCentricCoordinate(r, tval)) {
        return (tval >= tmin && tval <= tmax);
    }
    return false;
}